home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Practical Algorithms for Image Analysis
/
Practical Algorithms for Image Analysis.iso
/
CH_4.4
/
XPM
/
BDY.C
next >
Wrap
C/C++ Source or Header
|
1999-09-11
|
16KB
|
602 lines
/*
* bdy.c
*
* Practical Algorithms for Image Analysis
*
* Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
*/
/*
* BDY.C
*
* functions implementating C.T.Zahn's algorithm for boundary
* detection and representation
*
*/
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <math.h>
#include "ip.h"
#include "bdy.h"
#define WINDOW_ROWS 3
#define NDIRECTIONS 8
#define THRESH 1
#define MIN_POLY_SIZE 1
#define ZERO 0
#define ROOT2 1.414213562
#define ON 1
#define OFF 0
#undef SHOW_CURV_PT
#define DISPL_PAGE 1
#define RESET ON
#define IN_LIST 1
#define OUT_LIST 0
#define SHOW_CURV_PT
/* global variables */
extern struct curv_points *curv_head_in[NDIRECTIONS];
extern struct curv_points *curv_head_out[NDIRECTIONS];
extern struct curv_points *curv_tail_in[NDIRECTIONS];
extern struct curv_points *curv_tail_out[NDIRECTIONS];
extern struct polygon *poly_head_ptr;
extern struct polygon *poly_tail_ptr;
extern float *delta_phik, *delta_lk;
extern long ncp;
int page = DISPL_PAGE;
unsigned int d1, d2, d3, d4, d5, d6, b1, b2, b3, b4, b5, b6;
unsigned nbytes = 1;
/*
* generate curvature points using Zahn algorithm
* (ref: C. T. Zahn, SLAC report No. 70, Dec. 1966)
*/
void
curvature_points (unsigned char *window[], int ir, int jmax, int imax)
{
int jc;
for (jc = 0; jc < jmax - 2; jc++) {
d1 = *(*(window + (ir % WINDOW_ROWS)) + jc);
d2 = *(*(window + (ir % WINDOW_ROWS)) + jc + 1);
d3 = *(*(window + (ir % WINDOW_ROWS)) + jc + 2);
d4 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc);
d5 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 1);
d6 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 2);
horizontal (ir, jc);
}
for (jc = 0; jc < jmax - 1; jc++) {
b1 = *(*(window + (ir % WINDOW_ROWS)) + jc + 1);
b2 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 1);
b3 = *(*(window + ((ir + 2) % WINDOW_ROWS)) + jc + 1);
b4 = *(*(window + (ir % WINDOW_ROWS)) + jc);
b5 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc);
b6 = *(*(window + ((ir + 2) % WINDOW_ROWS)) + jc);
vertical (ir, jc);
}
if (ir == imax - WINDOW_ROWS) {
ir++;
for (jc = 0; jc < jmax - 2; jc++) {
d1 = *(*(window + (ir % WINDOW_ROWS)) + jc);
d2 = *(*(window + (ir % WINDOW_ROWS)) + jc + 1);
d3 = *(*(window + (ir % WINDOW_ROWS)) + jc + 2);
d4 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc);
d5 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 1);
d6 = *(*(window + ((ir + 1) % WINDOW_ROWS)) + jc + 2);
horizontal (ir, jc);
}
}
}
/*
* check 3x2 horizontal array (in a binary image) and determine
* direction codes for incoming and outgoing contour segment
*/
int
horizontal (i, j)
int i, j;
{
int in, out;
int err_flag = -1;
if (d2 >= THRESH) {
if (d5 == ZERO) {
if (d6 >= THRESH)
in = 3;
else if (d3 >= THRESH)
in = 4;
else
in = 5;
if (d4 >= THRESH)
out = 5;
else if (d1 >= THRESH)
out = 4;
else
out = 3;
}
else
return (err_flag);
}
else {
if (d5 >= THRESH) {
if (d1 >= THRESH)
in = 7;
else if (d4 >= THRESH)
in = 0;
else
in = 1;
if (d3 >= THRESH)
out = 1;
else if (d6 >= THRESH)
out = 0;
else
out = 7;
}
else
return (err_flag);
}
/*
* curvature point found!
* allocate memory and store it in linked list curv_points structure
*/
if (in != out) {
#ifdef SHOW_CURV_PT
printf (" horizontal: ir= %d, jc= %d, in= %d, out= %d\n",
2 * (i + 1), 2 * (j + 1) + 1, in, out);
#endif
if (curv_head_in[in] == NULL) {
curv_head_in[in] = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
curv_head_in[in]->prev = NULL;
curv_tail_in[in] = curv_head_in[in];
}
else {
curv_tail_in[in]->next = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
curv_tail_in[in]->next->prev = curv_tail_in[in];
curv_tail_in[in] = curv_tail_in[in]->next;
}
if (curv_head_out[out] == NULL) {
curv_head_out[out] = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
curv_head_out[out]->prev = NULL;
curv_tail_out[out] = curv_head_out[out];
}
else {
curv_tail_out[out]->next = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
curv_tail_out[out]->next->prev = curv_tail_out[out];
curv_tail_out[out] = curv_tail_out[out]->next;
}
ncp++;
curv_tail_in[in]->same_point = curv_tail_out[out];
curv_tail_in[in]->next = NULL;
curv_tail_out[out]->next = NULL;
curv_tail_in[in]->xn = curv_tail_out[out]->xn = 2 * (j + 1) + 1;
curv_tail_in[in]->yn = curv_tail_out[out]->yn = 2 * (i + 1);
curv_tail_in[in]->edge_in = curv_tail_out[out]->edge_in = in;
curv_tail_in[in]->edge_out = curv_tail_out[out]->edge_out = out;
}
return (1);
}
/*
* check 2x3 vertical array (in a binary image) and determine
* direction codes for incoming and outgoing contour segment
*/
int
vertical (i, j)
int i, j;
{
int in, out;
int err_flag = -1;
if (b2 >= THRESH) {
if (b5 == ZERO) {
if (b6 >= THRESH)
in = 1;
else if (b3 >= THRESH)
in = 2;
else
in = 3;
if (b4 >= THRESH)
out = 3;
else if (b1 >= THRESH)
out = 2;
else
out = 1;
}
else
return (err_flag);
}
else {
if (b5 >= THRESH) {
if (b1 >= THRESH)
in = 5;
else if (b4 >= THRESH)
in = 6;
else
in = 7;
if (b3 >= THRESH)
out = 7;
else if (b6 >= THRESH)
out = 6;
else
out = 5;
}
else
return (err_flag);
}
/*
* curvature point found!
* allocate memory and store it in linked list curv_points structure
*/
if (in != out) {
#ifdef SHOW_CURV_PT
printf (" vertical: ir= %d, jc= %d, in= %d, out= %d\n",
2 * (i + 1) + 1, 2 * (j + 1), in, out);
#endif
if (curv_head_in[in] == NULL) {
curv_head_in[in] = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
curv_head_in[in]->prev = NULL;
curv_tail_in[in] = curv_head_in[in];
}
else {
curv_tail_in[in]->next = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
curv_tail_in[in]->next->prev = curv_tail_in[in];
curv_tail_in[in] = curv_tail_in[in]->next;
}
if (curv_head_out[out] == NULL) {
curv_head_out[out] = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
curv_head_out[out]->prev = NULL;
curv_tail_out[out] = curv_head_out[out];
}
else {
curv_tail_out[out]->next = (struct curv_points *) calloc (nbytes, sizeof (struct curv_points));
curv_tail_out[out]->next->prev = curv_tail_out[out];
curv_tail_out[out] = curv_tail_out[out]->next;
}
ncp++;
curv_tail_in[in]->same_point = curv_tail_out[out];
curv_tail_in[in]->next = NULL;
curv_tail_out[out]->next = NULL;
curv_tail_in[in]->xn = curv_tail_out[out]->xn = 2 * (j + 1);
curv_tail_in[in]->yn = curv_tail_out[out]->yn = 2 * (i + 1) + 1;
curv_tail_in[in]->edge_in = curv_tail_out[out]->edge_in = in;
curv_tail_in[in]->edge_out = curv_tail_out[out]->edge_out = out;
}
return (1);
}
/*
* link up all curvature points into closed polygons
*/
void
linkage (Image * imgIn, Image * imgOut, int value)
{
struct polygon *dummy_poly_ptr;
struct curv_points *first_point;
float *d_phi_head, *d_l_head;
int m, c;
char in_buf[IN_BUF_LEN];
do {
d_phi_head = delta_phik;
d_l_head = delta_lk;
for (m = 0; m < NDIRECTIONS; m++)
if ((first_point = curv_head_out[m]) != NULL) {
poly (first_point);
break;
}
} while (first_point != NULL);
if (ncp != 0)
printf ("...something wrong, didn't find all polygons!\n");
if (poly_head_ptr == NULL) {
printf ("...no objects found to analyze!\n");
return;
}
/*
* polygon analysis
*/
printf ("...analyze a boundary?(y/n) -- ");
while ((c = readlin (in_buf)) == 'y') {
dummy_poly_ptr = select_poly (poly_head_ptr, imgOut, value);
printf ("\n...analyze another boundary?(y/n)");
}
}
/*
* create a closed polygon given a starting curvature point
*/
void
poly (first_point)
struct curv_points *first_point;
{
struct curv_points *next_point, *prev_point, *match_in_list ();
if (poly_head_ptr == NULL) {
poly_head_ptr = (struct polygon *) calloc (nbytes, sizeof (struct polygon));
poly_tail_ptr = poly_head_ptr;
poly_head_ptr->prev_poly = NULL;
}
else {
poly_tail_ptr->next_poly = (struct polygon *) calloc (nbytes, sizeof (struct polygon));
poly_tail_ptr->next_poly->prev_poly = poly_tail_ptr;
poly_tail_ptr = poly_tail_ptr->next_poly;
}
poly_tail_ptr->next_poly = NULL;
prev_point = first_point;
next_point = match_in_list (prev_point);
poly_tail_ptr->d_phi_ptr = delta_phik;
poly_tail_ptr->d_l_ptr = delta_lk;
poly_tail_ptr->poly_points = 0;
poly_tail_ptr->total_delta_phi = (float) 0;
poly_tail_ptr->first_x = first_point->xn;
poly_tail_ptr->first_y = first_point->yn;
poly_tail_ptr->first_edge_out = first_point->edge_out;
create_edge (prev_point, next_point);
delete_list (prev_point, OUT_LIST);
prev_point = next_point->same_point;
delete_list (next_point, IN_LIST);
ncp--;
poly_tail_ptr->poly_points++;
poly_tail_ptr->total_delta_phi = poly_tail_ptr->total_delta_phi + *delta_phik;
delta_lk++;
delta_phik++;
do {
next_point = match_in_list (prev_point);
create_edge (prev_point, next_point);
delete_list (prev_point, OUT_LIST);
prev_point = next_point->same_point;
delete_list (next_point, IN_LIST);
ncp--;
poly_tail_ptr->poly_points++;
poly_tail_ptr->total_delta_phi = poly_tail_ptr->total_delta_phi
+ *delta_phik;
delta_lk++;
delta_phik++;
if (ncp < 0) {
printf ("Something wrong, points<0\n");
exit (1);
}
}
while (prev_point != first_point);
if (poly_tail_ptr->poly_points <= MIN_POLY_SIZE) {
if (poly_tail_ptr->prev_poly == NULL)
poly_head_ptr = NULL;
else {
poly_tail_ptr = poly_tail_ptr->prev_poly;
free (poly_tail_ptr->next_poly);
poly_tail_ptr->next_poly = NULL;
}
}
}
/*
* given a point in the out-list, find the next point
* in the in-list with edge-out(out-list) = edge-in(in-list)
*/
struct curv_points *
match_in_list (current_point)
struct curv_points *current_point;
{
struct curv_points *tail_point, *head_point;
int direction;
int xcurr, ycurr, xnext, ynext;
xcurr = current_point->xn;
ycurr = current_point->yn;
printf ("match_in_list: current point = (%d, %d)\n", xcurr, ycurr);
direction = current_point->edge_out;
tail_point = curv_tail_in[direction];
head_point = curv_head_in[direction];
while ((head_point != NULL) || (tail_point != NULL)) {
switch (direction) {
case 0:
ynext = head_point->yn;
xnext = head_point->xn;
if ((ycurr == ynext) && (xnext > xcurr))
return (head_point);
break;
case 4:
ynext = tail_point->yn;
xnext = tail_point->xn;
if ((ycurr == ynext) && (xnext < xcurr))
return (tail_point);
break;
case 2:
ynext = tail_point->yn;
xnext = tail_point->xn;
if ((xcurr == xnext) && (ynext < ycurr))
return (tail_point);
break;
case 6:
ynext = head_point->yn;
xnext = head_point->xn;
if ((xcurr == xnext) && (ynext > ycurr))
return (head_point);
break;
case 1:
ynext = tail_point->yn;
xnext = tail_point->xn;
if (((xcurr + ycurr) == (xnext + ynext)) &&
(xnext > xcurr) && (ynext < ycurr))
return (tail_point);
break;
case 5:
ynext = head_point->yn;
xnext = head_point->xn;
if (((xcurr + ycurr) == (xnext + ynext)) &&
(xnext < xcurr) && (ynext > ycurr))
return (head_point);
break;
case 3:
ynext = tail_point->yn;
xnext = tail_point->xn;
if (((xcurr - ycurr) == (xnext - ynext)) &&
(xnext < xcurr) && (ynext < ycurr))
return (tail_point);
break;
case 7:
ynext = head_point->yn;
xnext = head_point->xn;
if (((xcurr - ycurr) == (xnext - ynext)) &&
(xnext > xcurr) && (ynext > ycurr))
return (head_point);
break;
}
tail_point = tail_point->prev;
head_point = head_point->next;
}
printf ("...no match found in outlist[%d]\n", direction);
exit (1);
}
/*
* delete curvature point from either in-list or out-list
*/
void
delete_list (current_point, list)
struct curv_points *current_point;
int list;
{
int direction;
if (current_point == NULL)
printf ("...current point can't be NULL!\n");
if ((current_point->prev == NULL) && (current_point->next == NULL)) {
if (list == IN_LIST) {
direction = current_point->edge_in;
curv_head_in[direction] = NULL;
curv_tail_in[direction] = NULL;
}
else {
direction = current_point->edge_out;
curv_head_out[direction] = NULL;
curv_tail_out[direction] = NULL;
}
}
else if (current_point->prev == NULL) {
if (list == IN_LIST) {
direction = current_point->edge_in;
curv_head_in[direction] = current_point->next;
}
else {
direction = current_point->edge_out;
curv_head_out[direction] = current_point->next;
}
current_point->next->prev = NULL;
}
else if (current_point->next == NULL) {
if (list == IN_LIST) {
direction = current_point->edge_in;
curv_tail_in[direction] = current_point->prev;
}
else {
direction = current_point->edge_out;
curv_tail_out[direction] = current_point->prev;
}
current_point->prev->next = NULL;
}
else {
current_point->prev->next = current_point->next;
current_point->next->prev = current_point->prev;
}
free (current_point);
}
void
print_curv ()
{
int x, y;
struct curv_points *temp_head;
for (x = 0; x < NDIRECTIONS; x++) {
y = 0;
temp_head = curv_head_in[x];
while (temp_head != NULL) {
y++;
temp_head = temp_head->next;
}
if (y != 0)
printf ("inlist[%d] = %d\n", x, y);
}
for (x = 0; x < NDIRECTIONS; x++) {
y = 0;
temp_head = curv_head_out[x];
while (temp_head != NULL) {
y++;
temp_head = temp_head->next;
}
if (y != 0)
printf ("outlist[%d] = %d\n", x, y);
}
}
/*
* create an edge from old-point to new-point
*/
void
create_edge (old_point, new_point)
struct curv_points *old_point, *new_point;
{
int phi;
switch (new_point->edge_in) {
case 0:
case 4:
*delta_lk = (float) abs (new_point->xn - old_point->xn);
phi = new_point->edge_out - new_point->edge_in;
if (phi == 7)
phi = -1;
*delta_phik = (float) phi;
break;
case 2:
case 6:
*delta_lk = (float) abs (new_point->yn - old_point->yn);
*delta_phik = (float) (new_point->edge_out - new_point->edge_in);
break;
default:
*delta_lk = (float) abs (new_point->xn - old_point->xn) * (float) ROOT2;
phi = new_point->edge_out - new_point->edge_in;
if (phi == -7)
phi = 1;
else if (phi == -6)
phi = 2;
else if (phi == 6)
phi = -2;
*delta_phik = (float) phi;
break;
}
}